package com.bravo.other.rate_limiter.slide;

import java.util.Arrays;

public class SlideWindow {

     // 格子数组
    private  long[] slots;
    // 每个格子的时间间隔，单位：m秒
    private   int SLOT_INTERVAL ;
    // 窗口大小，单位：m秒
    private   int WINDOW_SIZE ;
    // 最大请求数
    private   int MAX_REQUESTS;
    // 上次请求时间
    private   long lastRequestTime;


    public SlideWindow(Integer maxRequests, Integer windowSize, Integer slotInterval) {
        if (maxRequests != null) {
            this.MAX_REQUESTS = maxRequests;
        }
        if (windowSize != null) {
            this.WINDOW_SIZE = windowSize;
        }
        if (slotInterval != null) {
            this.SLOT_INTERVAL = slotInterval;
        }
        this.slots = new long[WINDOW_SIZE / SLOT_INTERVAL];
        this.lastRequestTime = System.currentTimeMillis();
    }


    /**
     * 判断是否超出限制
     * 然后增加计数
     * 超过格子数怎么办 动态迁移还是使用双指针
     * 删除的是上次和当前格子数之间的格子
     *  通过取模运算无感的变成环形数组
     * 1 确定在哪个格子
     * 2 减去过期的格子
     * 3 判断格子数是否超出限制
     * 4 添加当前格子
     *
     */
    public boolean isLimitExceeded() {
        long currentTimeMillis = System.currentTimeMillis();
        long interval = currentTimeMillis - lastRequestTime;
        int currentSlot = (int) ((interval / SLOT_INTERVAL) % slots.length);
        long windowStartTime = interval - WINDOW_SIZE;
        if (windowStartTime>0){
           reset();
        }
        int windowStartSlot = (int) ((interval / SLOT_INTERVAL) % slots.length);
        // 清除过期的格子
        clearExpire(windowStartSlot);
        // 计算单个格子数
        if (slots[currentSlot] >= MAX_REQUESTS) {
            return false;
        }
        long totalCount = 0L;
        // 计算总体格子数
        for (int i = windowStartSlot; i < currentSlot; i++) {
            totalCount += slots[i];
        }
        if (totalCount >= MAX_REQUESTS){
            return false;
        }
        // 增加当前格子数
        slots[currentSlot]++;
        return true;
    }

    public synchronized void reset() {
        Arrays.fill(slots, 0);
    }

    public synchronized void clearExpire(int  index) {
        for (int i = 0; i < index; i++){
            slots[i] = 0;
        }
    }

    // 获取当前窗口内的请求数
    public synchronized long getCurrentCount() {
        long totalCount = 0;
        for (long slot : slots) {
            totalCount += slot;
        }
        return totalCount;
    }
}
